#!/usr/bin/env python3
"""
机器学习引擎 - 配置文件

本模块提供了机器学习引擎的配置管理功能，包括模型参数、
训练设置、数据路径等配置项的管理。

主要功能：
- 配置管理：集中管理所有配置项
- 环境配置：支持不同环境的配置
- 参数验证：配置参数的有效性检查
- 配置热更新：运行时配置更新
- 配置持久化：配置的保存和加载

配置项包括：
- 数据配置：数据集路径、预处理参数
- 模型配置：算法参数、超参数设置
- 训练配置：训练参数、验证设置
- 预测配置：预测参数、缓存设置
- 系统配置：日志级别、性能设置
"""

import os
import json
from typing import Dict, Any, Optional
from dataclasses import dataclass, asdict

@dataclass
class DataConfig:
    """数据配置类"""
    # 数据路径
    raw_data_dir: str = "data/raw"
    processed_data_dir: str = "data/processed"
    enhanced_data_dir: str = "data/enhanced"
    
    # 数据增强参数
    augmentation_ratio: float = 15.0  # 数据增强倍数
    synonym_replacement_prob: float = 0.3  # 同义词替换概率
    sentence_transformation_prob: float = 0.2  # 句式变换概率
    multilingual_prob: float = 0.1  # 多语言增强概率
    
    # 数据平衡参数
    min_samples_per_label: int = 50  # 每个标签最少样本数
    max_samples_per_label: int = 200  # 每个标签最多样本数
    
    # 数据预处理参数
    max_text_length: int = 1000  # 最大文本长度
    min_text_length: int = 5  # 最小文本长度

@dataclass
class ModelConfig:
    """模型配置类"""
    # 模型类型
    default_model_type: str = "ensemble"
    available_models: list = None
    
    # 朴素贝叶斯参数
    naive_bayes_alpha: float = 0.1
    
    # 逻辑回归参数
    logistic_regression_C: float = 1.0
    logistic_regression_max_iter: int = 1000
    
    # 随机森林参数
    random_forest_n_estimators: int = 100
    random_forest_max_depth: int = 10
    random_forest_min_samples_split: int = 5
    random_forest_min_samples_leaf: int = 2
    
    # 支持向量机参数
    svm_C: float = 1.0
    svm_kernel: str = "rbf"
    
    # 神经网络参数
    neural_network_hidden_layers: tuple = (100, 50)
    neural_network_max_iter: int = 1000
    
    # XGBoost参数
    xgboost_n_estimators: int = 100
    xgboost_max_depth: int = 6
    xgboost_learning_rate: float = 0.1
    
    def __post_init__(self):
        if self.available_models is None:
            self.available_models = [
                "naive_bayes", "logistic_regression", "random_forest",
                "svm", "neural_network", "xgboost", "ensemble"
            ]

@dataclass
class TrainingConfig:
    """训练配置类"""
    # 训练参数
    test_size: float = 0.2  # 测试集比例
    random_state: int = 42  # 随机种子
    cv_folds: int = 5  # 交叉验证折数
    
    # 特征工程参数
    tfidf_max_features: int = 5000
    tfidf_ngram_range: tuple = (1, 3)
    tfidf_min_df: int = 1
    tfidf_max_df: float = 0.95
    
    # 特征选择参数
    feature_selection_k: int = 1000
    pca_components: int = 500
    
    # Word2Vec参数
    word2vec_vector_size: int = 100
    word2vec_window: int = 5
    word2vec_min_count: int = 1
    word2vec_epochs: int = 10
    
    # Doc2Vec参数
    doc2vec_vector_size: int = 100
    doc2vec_window: int = 5
    doc2vec_min_count: int = 1
    doc2vec_epochs: int = 10

@dataclass
class PredictionConfig:
    """预测配置类"""
    # 预测参数
    batch_size: int = 100  # 批量预测大小
    confidence_threshold: float = 0.5  # 置信度阈值
    
    # 缓存参数
    enable_cache: bool = True
    cache_size: int = 1000
    cache_ttl: int = 3600  # 缓存生存时间（秒）
    
    # 性能参数
    max_prediction_time: float = 1.0  # 最大预测时间（秒）
    enable_parallel: bool = True  # 是否启用并行预测

@dataclass
class SystemConfig:
    """系统配置类"""
    # 日志配置
    log_level: str = "INFO"
    log_file: str = "logs/ml_engine.log"
    log_format: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
    
    # 性能配置
    max_memory_usage: float = 0.8  # 最大内存使用率
    enable_gpu: bool = False  # 是否启用GPU
    
    # 安全配置
    enable_model_validation: bool = True  # 是否启用模型验证
    max_model_size: int = 100 * 1024 * 1024  # 最大模型大小（字节）

class MLConfig:
    """
    机器学习配置管理器
    
    提供配置的集中管理、验证和持久化功能。
    """
    
    def __init__(self, config_file: str = None):
        """
        初始化配置管理器
        
        参数:
            config_file (str): 配置文件路径
        """
        self.config_file = config_file or "ml_engine/config/settings.json"
        
        # 初始化默认配置
        self.data_config = DataConfig()
        self.model_config = ModelConfig()
        self.training_config = TrainingConfig()
        self.prediction_config = PredictionConfig()
        self.system_config = SystemConfig()
        
        # 加载配置
        self.load_config()
    
    def load_config(self):
        """从文件加载配置"""
        if os.path.exists(self.config_file):
            try:
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    config_data = json.load(f)
                
                # 更新配置
                if 'data' in config_data:
                    self.data_config = DataConfig(**config_data['data'])
                if 'model' in config_data:
                    self.model_config = ModelConfig(**config_data['model'])
                if 'training' in config_data:
                    self.training_config = TrainingConfig(**config_data['training'])
                if 'prediction' in config_data:
                    self.prediction_config = PredictionConfig(**config_data['prediction'])
                if 'system' in config_data:
                    self.system_config = SystemConfig(**config_data['system'])
                
                print(f"配置已从 {self.config_file} 加载")
                
            except Exception as e:
                print(f"加载配置失败: {e}")
                print("使用默认配置")
        else:
            print(f"配置文件 {self.config_file} 不存在，使用默认配置")
    
    def save_config(self):
        """保存配置到文件"""
        try:
            # 确保配置目录存在
            os.makedirs(os.path.dirname(self.config_file), exist_ok=True)
            
            config_data = {
                'data': asdict(self.data_config),
                'model': asdict(self.model_config),
                'training': asdict(self.training_config),
                'prediction': asdict(self.prediction_config),
                'system': asdict(self.system_config)
            }
            
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(config_data, f, ensure_ascii=False, indent=2)
            
            print(f"配置已保存到 {self.config_file}")
            
        except Exception as e:
            print(f"保存配置失败: {e}")
    
    def validate_config(self) -> Dict[str, Any]:
        """验证配置的有效性"""
        validation_results = {
            'valid': True,
            'errors': [],
            'warnings': []
        }
        
        # 验证数据配置
        if self.data_config.augmentation_ratio < 1.0:
            validation_results['errors'].append("数据增强倍数必须大于等于1.0")
        
        if self.data_config.min_samples_per_label < 1:
            validation_results['errors'].append("每个标签最少样本数必须大于0")
        
        # 验证模型配置
        if self.model_config.default_model_type not in self.model_config.available_models:
            validation_results['errors'].append(f"默认模型类型 {self.model_config.default_model_type} 不在可用模型中")
        
        # 验证训练配置
        if not (0 < self.training_config.test_size < 1):
            validation_results['errors'].append("测试集比例必须在0和1之间")
        
        if self.training_config.cv_folds < 2:
            validation_results['errors'].append("交叉验证折数必须大于等于2")
        
        # 验证预测配置
        if not (0 < self.prediction_config.confidence_threshold <= 1):
            validation_results['errors'].append("置信度阈值必须在0和1之间")
        
        if self.prediction_config.batch_size < 1:
            validation_results['errors'].append("批量大小必须大于0")
        
        # 验证系统配置
        valid_log_levels = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
        if self.system_config.log_level not in valid_log_levels:
            validation_results['errors'].append(f"日志级别必须是 {valid_log_levels} 之一")
        
        if not (0 < self.system_config.max_memory_usage <= 1):
            validation_results['errors'].append("最大内存使用率必须在0和1之间")
        
        # 检查是否有错误
        if validation_results['errors']:
            validation_results['valid'] = False
        
        return validation_results
    
    def get_config_dict(self) -> Dict[str, Any]:
        """获取完整配置字典"""
        return {
            'data': asdict(self.data_config),
            'model': asdict(self.model_config),
            'training': asdict(self.training_config),
            'prediction': asdict(self.prediction_config),
            'system': asdict(self.system_config)
        }
    
    def update_config(self, section: str, **kwargs):
        """
        更新配置项
        
        参数:
            section (str): 配置节名称
            **kwargs: 要更新的配置项
        """
        if section == 'data':
            for key, value in kwargs.items():
                if hasattr(self.data_config, key):
                    setattr(self.data_config, key, value)
        elif section == 'model':
            for key, value in kwargs.items():
                if hasattr(self.model_config, key):
                    setattr(self.model_config, key, value)
        elif section == 'training':
            for key, value in kwargs.items():
                if hasattr(self.training_config, key):
                    setattr(self.training_config, key, value)
        elif section == 'prediction':
            for key, value in kwargs.items():
                if hasattr(self.prediction_config, key):
                    setattr(self.prediction_config, key, value)
        elif section == 'system':
            for key, value in kwargs.items():
                if hasattr(self.system_config, key):
                    setattr(self.system_config, key, value)
        else:
            raise ValueError(f"未知的配置节: {section}")
    
    def reset_to_defaults(self):
        """重置为默认配置"""
        self.data_config = DataConfig()
        self.model_config = ModelConfig()
        self.training_config = TrainingConfig()
        self.prediction_config = PredictionConfig()
        self.system_config = SystemConfig()
        print("配置已重置为默认值")

# 全局配置实例
config = MLConfig()

if __name__ == "__main__":
    """演示配置管理器的功能"""
    
    # 创建配置管理器
    ml_config = MLConfig()
    
    # 显示当前配置
    print("当前配置:")
    config_dict = ml_config.get_config_dict()
    for section, settings in config_dict.items():
        print(f"\n{section.upper()}:")
        for key, value in settings.items():
            print(f"  {key}: {value}")
    
    # 验证配置
    validation = ml_config.validate_config()
    print(f"\n配置验证结果:")
    print(f"  有效: {validation['valid']}")
    if validation['errors']:
        print(f"  错误: {validation['errors']}")
    if validation['warnings']:
        print(f"  警告: {validation['warnings']}")
    
    # 更新配置
    print(f"\n更新配置...")
    ml_config.update_config('training', test_size=0.3, cv_folds=10)
    ml_config.update_config('prediction', confidence_threshold=0.7)
    
    # 保存配置
    ml_config.save_config()
    
    print("配置管理演示完成")
